from django.shortcuts import render,get_object_or_404,redirect,HttpResponse
from django.db.models import Q
from ..models import Device,Log,DevicesBackup
from netmiko import ConnectHandler
import time
from datetime import datetime
import threading
from queue import Queue
from django.utils.safestring import mark_safe
import logging
import os


#导入插件
from ..utlis import pagination


"""
已实现备份功能；

待优化项目：
    1、添加一个全选功能，当设备数量过多时，必须有全选
    2、当配置备份完成后，提供一个配置下载的界面
    3、增加LOG日志功能
"""



def backup(request):
    if request.method == 'GET':

        data_dict = {}
        search_data = request.GET.get("q", "")
        q1=Q()
        if search_data:
            #data_dict["ip_address__contains"] = search_data

            q1.connector = 'OR'
            q1.children.append(('ip_address', search_data))
            q1.children.append(('diqu', search_data))

            # 定义当前页
            page = int(request.GET.get('page', 1))

            # 定义页码显示多少数据
            page_size = 2

            # 定义每页开始位置
            start = (page - 1) * page_size

            # 定义每页结束的位置
            end = page * page_size

            devices = Device.objects.filter(q1)[start:end]

            # 总计总数据
            total_count = Device.objects.filter(q1).count()

            # 计算出总页面
            total_page_count, div = divmod(total_count, page_size)
            if div:
                total_page_count += 1

            # 计算出，显示当前页的前5页和后5页
            plus = 5

            if total_page_count <= 2 * plus + 1:
                # 当数据库中数据量少时，小于11页
                start_page = 1  # 开始页=1
                end_page = total_page_count  # 结束也=当前总页码
            else:
                # 当前页码<5时
                if page <= plus:
                    start_page = 1
                    end_page = 2 * plus + 1
                else:
                    # 当前页码 + 要显示的页码 > 总页码时
                    if (page + plus) > total_page_count:
                        start_page = total_page_count - 2 * plus
                        end_page = total_page_count
                    else:
                        start_page = page - plus
                        end_page = page + plus
            # 页码
            # 定义一个列表
            page_str_list = []

            # 首页
            page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))

            # 上一页
            if page > 1:
                prev = '<li><a href="?page={}">上一页</a></li>'.format(page - 1)
            else:
                prev = '<li><a href="?page={}">上一页</a></li>'.format(1)
            page_str_list.append(prev)

            # for循环，生成开始页和结束页
            for i in range(start_page, end_page + 1):
                # 如果i=当前页，在前端加个样式，如果不等于当前页则不添加
                if i == page:
                    ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
                else:
                    ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
                # 将生成出来的页码写入到列表中
                page_str_list.append(ele)

            # 下一页
            if page < total_page_count:
                prev = '<li><a href="?page={}">下一页</a></li>'.format(page + 1)
            else:
                prev = '<li><a href="?page={}">下一页</a></li>'.format(total_page_count)
            page_str_list.append(prev)

            # 尾页
            page_str_list.append('<li><a href="?page={}">尾页</a></li>'.format(total_page_count))

            page_string = mark_safe("".join(page_str_list))

            return render(request, "backup.html", {"devices": devices, "page_string": page_string})

        else:
            #定义当前页
            page = int(request.GET.get('page',1))

            #定义页码显示多少数据
            page_size = 2

            #定义每页开始位置
            start = (page - 1)* page_size

            #定义每页结束的位置
            end = page * page_size

            devices = Device.objects.filter(**data_dict)[start:end]


            #总计总数据
            total_count = Device.objects.filter(**data_dict).count()

            #计算出总页面
            total_page_count, div = divmod(total_count,page_size)
            if div:
                total_page_count += 1

            #计算出，显示当前页的前5页和后5页
            plus = 5

            if total_page_count <= 2 * plus + 1:
                # 当数据库中数据量少时，小于11页
                start_page = 1  # 开始页=1
                end_page = total_page_count  # 结束也=当前总页码
            else:
                # 当前页码<5时
                if page <= plus:
                    start_page = 1
                    end_page = 2 * plus + 1
                else:
                    # 当前页码 + 要显示的页码 > 总页码时
                    if (page + plus) > total_page_count:
                        start_page = total_page_count - 2 * plus
                        end_page = total_page_count
                    else:
                        start_page = page - plus
                        end_page = page + plus
            # 页码
            # 定义一个列表
            page_str_list = []

            # 首页
            page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))

            # 上一页
            if page > 1:
                prev = '<li><a href="?page={}">上一页</a></li>'.format(page - 1)
            else:
                prev = '<li><a href="?page={}">上一页</a></li>'.format(1)
            page_str_list.append(prev)

            # for循环，生成开始页和结束页
            for i in range(start_page, end_page + 1):
                # 如果i=当前页，在前端加个样式，如果不等于当前页则不添加
                if i == page:
                    ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
                else:
                    ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
                # 将生成出来的页码写入到列表中
                page_str_list.append(ele)

            # 下一页
            if page < total_page_count:
                prev = '<li><a href="?page={}">下一页</a></li>'.format(page + 1)
            else:
                prev = '<li><a href="?page={}">下一页</a></li>'.format(total_page_count)
            page_str_list.append(prev)

            # 尾页
            page_str_list.append('<li><a href="?page={}">尾页</a></li>'.format(total_page_count))

            page_string = mark_safe("".join(page_str_list))

            return render(request, "backup.html",{"devices":devices,"page_string":page_string})


    elif request.method == 'POST':
        now = datetime.now()
        date = f'{now.month}_{now.day}_{now.year}'
        result =[]
        #通过POST请求获取到在页面中选择的设备所对应的ID
        selected_device_id = request.POST.getlist('device')
        print(selected_device_id)

        #判断返回的字符串是否为空，如果是全选设备，第一行会产生一个为空的字符串
        while '' in selected_device_id:
            selected_device_id.remove('')

        for x in selected_device_id:
            try:
                dev = get_object_or_404(Device,pk=x)
                #判断设备类型
                if dev.dev_name.lower() == 'cisco':
                    def session(ip,output):
                        conn = ConnectHandler(**sw)
                        output = conn.send_config_from_file(f'/cmd/cisco.cmd.txt')
                        #now = datetime.now()
                        #date = f'{now.month}_{now.day}_{now.year}'

                        #定义备份路径
                        with open(f"/cmd/backup/{dev.ip_address}",'a') as f:
                            f.write(output)
                            result.append(f'{dev.ip_address}设备配置备份成功')

                    sw ={
                        'device_type': "cisco",
                        'ip': dev.ip_address,
                        'username': dev.username,
                        'password': dev.password,
                    }
                    t = threading.Thread(target=session, args=(dev.ip_address, Queue()))
                    t.start()
                elif dev.dev_name.lower() == 'huawei':
                    def session(ip,output):
                        conn = ConnectHandler(**sw)
                        output = conn.send_config_from_file(f'/Users/yunhui.han/yunwei/ywpt/netdevops/commd/huawei_cmd.txt')
                        now = datetime.now()
                        date = f'{now.month}_{now.day}_{now.year}'
                        with open(f"/Users/yunhui.han/yunwei/ywpt/netdevops/commd/backup/"+dev.dev_name+"_"+date+".txt", 'a') as f:
                            f.write(output)

                        data_dic = {
                            "title": dev.dev_name + "_" + date + ".txt",
                            "time": now,
                            "ip": ip,
                        }
                        DevicesBackup.objects.create(**data_dic)
                    ip1 = []
                    ip1.append(dev.ip_address)
                    for ip in ip1:
                        sw = {'device_type': "huawei", 'ip': ip, 'username': dev.username, 'password': dev.password}
                        t = threading.Thread(target=session, args=(ip, Queue()))
                        t.start()
                        result.append(f'{ip}配置备份成功!')



                # #将定义的信息写入到数据库中
                # log = Log(target=dev.ip_address,action="Backup Configuration",status='seccess',message='No Error')
                # log.save()
            except Exception as e:
                # log = Log(target=dev.ip_address,action='Backup Configuration',status='Error',messages=e)
                # log.save()
                result.append(f'{dev.ip_address}配置备份失败，请查看日志!')
        result = '\n'.join(result)

        time.sleep(3)
        return render(request, 'verify_config.html', {"result":result})




"""
配置下载
"""
def download(request):
    nid = request.GET.get('nid')

    if nid:
        file_name = DevicesBackup.objects.filter(id=nid).first()
        file_path = f"../ywpt/netdevops/commd/backup/{file_name.title}"
        with open(file_path,'rb') as file:
            file_data = file.read()

        response = HttpResponse(file_data,content_type='application/octet-stream')
        response['Content-Disposition'] = 'attachment; filename="{}"'.format(os.path.basename(file_path))
        return response


    data_dict = {}
    search_data = request.GET.get("q","")
    if search_data:
        # 在数据库中查询IP的搜索语句
        data_dict["ip__contains"] = search_data

    if search_data:
        data_dict["ip__contains"] = search_data

    page = int(request.GET.get('page', 1))

    page_size = 15

    start = (page - 1) * page_size
    end = page * page_size

    form = DevicesBackup.objects.filter(**data_dict)[start:end]

    # 计算出总页码
    # 数据总条数
    total_count = DevicesBackup.objects.filter(**data_dict).count()
    # python自带divmod计算；总条数 除以 分页显示数量  = 应该显示多少页码；如果有余数，则加1
    total_page_count, div = divmod(total_count, page_size)
    if div:
        total_page_count += 1

    # 计算出，显示当前页的前5页和后5页；
    plus = 5

    if total_page_count <= 2 * plus + 1:
        start_page = 1  # 开始页=1
        end_page = total_page_count  # 结束也=当前总页码

    else:
        if page <= plus:
            start_page = 1
            end_page = 2 * plus + 1
        else:
            if (page + plus) > total_page_count:
                start_page = total_page_count - 2 * plus
                end_page = total_page_count
            else:
                start_page = page - plus
                end_page = page + plus

    page_str_list = []
    # 首页
    page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))

    if page > 1:
        prev = '<li><a href="?page={}">上一页</a></li>'.format(page - 1)
    else:
        prev = '<li><a href="?page={}">上一页</a></li>'.format(1)
    page_str_list.append(prev)

    for i in range(start_page, end_page + 1):
        if i == page:
            ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
        else:
            ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
        page_str_list.append(ele)

    if page < total_page_count:
        prev = '<li><a href="?page={}">下一页</a></li>'.format(page + 1)
    else:
        prev = '<li><a href="?page={}">下一页</a></li>'.format(total_page_count)
    page_str_list.append(prev)

    # 尾页
    page_str_list.append('<li><a href="?page={}">尾页</a></li>'.format(total_page_count))

    # django默认无法将标签语法在界面展示，会判定为不合法字符串，通过maek_safe判定一下，认为是合法的
    page_string = mark_safe("".join(page_str_list))
    return render(request, "down.html", {"form":form, "page_string": page_string})



"""
配置删除
"""
def delete(request):
    nid = request.GET.get('nid')

    file_name = DevicesBackup.objects.filter(id=nid).first()
    file_path = f"../ywpt/netdevops/commd/backup/{file_name.title}"
    os.remove(file_path)
    DevicesBackup.objects.filter(id=nid).delete()
    return redirect("/backup/download/")


